package com.ruoyi.rva.domain;

import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.rva.mapper.RvaPropertyMapper;
import com.ruoyi.rva.mapper.RvaRelationMapper;
import com.ruoyi.rva.util.RvaJsonUtils;
import com.ruoyi.rva.util.RvaUtils;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import java.util.*;
import java.util.stream.Stream;

/**
 * 对象对象 rva_object
 * 
 * @author jiaodacailei
 * @date 2021-07-27
 */
public class RvaObject extends BaseEntity
{
    private static final long serialVersionUID = 1L;

    /** ID */
    private String id;

    /** 编号 */
    @Excel(name = "编号")
    private String no;

    /** 名称 */
    @Excel(name = "名称")
    private String name;

    /** 索引 */
    @Excel(name = "索引")
    private Long idx;

    /** 模块前缀 */
    @Excel(name = "模块前缀")
    private String module;

    /** 状态（0关系表 1普通表） */
    @Excel(name = "状态", readConverterExp = "0=关系表,1=普通表")
    private String status;

    /** 说明 */
    @Excel(name = "说明")
    private String description;

    /** 名称属性名 */
    @Excel(name = "名称属性名")
    private String propNameName;

    /** 逻辑删除属性名 */
    @Excel(name = "逻辑删除属性名")
    private String propNameDel;

    /** 层级编号属性名 */
    @Excel(name = "层级编号属性名")
    private String propNameNo;

    /** 主键属性名 */
    @Excel(name = "主键属性名")
    private String propNameKey;

    /** 创建人属性名 */
    @Excel(name = "创建人属性名")
    private String propNameCreateBy;

    /** 创建时间属性名 */
    @Excel(name = "创建时间属性名")
    private String propNameCreateTime;

    /** 修改人属性名 */
    @Excel(name = "修改人属性名")
    private String propNameUpdateBy;

    /** 修改时间属性名 */
    @Excel(name = "修改时间属性名")
    private String propNameUpdateTime;

    /** 唯一键 */
    @Excel(name = "唯一键")
    private String uniques;

    /** 属性索引最大值 */
    @Excel(name = "属性索引最大值")
    private Integer propIndexMax;

    /** 关系索引最大值 */
    @Excel(name = "关系索引最大值")
    private Integer relationIndexMax;

    /** 其他数据 */
    @Excel(name = "其他数据")
    private String data;

    public void setId(String id) 
    {
        this.id = id;
    }

    public String getId() 
    {
        return id;
    }
    public void setNo(String no) 
    {
        this.no = no;
    }

    public String getNo() 
    {
        return no;
    }
    public void setName(String name) 
    {
        this.name = name;
    }

    public String getName() 
    {
        return name;
    }
    public void setIdx(Long idx) 
    {
        this.idx = idx;
    }

    public Long getIdx() 
    {
        return idx;
    }
    public void setModule(String module) 
    {
        this.module = module;
    }

    public String getModule() 
    {
        return module;
    }
    public void setStatus(String status) 
    {
        this.status = status;
    }

    public String getStatus() 
    {
        return status;
    }
    public void setDescription(String description) 
    {
        this.description = description;
    }

    public String getDescription() 
    {
        return description;
    }
    public void setPropNameName(String propNameName) 
    {
        this.propNameName = propNameName;
    }

    public String getPropNameName() 
    {
        return propNameName;
    }
    public void setPropNameDel(String propNameDel) 
    {
        this.propNameDel = propNameDel;
    }

    public String getPropNameDel() 
    {
        return propNameDel;
    }
    public void setPropNameNo(String propNameNo) 
    {
        this.propNameNo = propNameNo;
    }

    public String getPropNameNo() 
    {
        return propNameNo;
    }
    public void setPropNameKey(String propNameKey) 
    {
        this.propNameKey = propNameKey;
    }

    public String getPropNameKey() 
    {
        return propNameKey;
    }

    public String getPropNameCreateBy() {
        return propNameCreateBy;
    }

    public void setPropNameCreateBy(String propNameCreateBy) {
        this.propNameCreateBy = propNameCreateBy;
    }

    public String getPropNameCreateTime() {
        return propNameCreateTime;
    }

    public void setPropNameCreateTime(String propNameCreateTime) {
        this.propNameCreateTime = propNameCreateTime;
    }

    public String getPropNameUpdateBy() {
        return propNameUpdateBy;
    }

    public void setPropNameUpdateBy(String propNameUpdateBy) {
        this.propNameUpdateBy = propNameUpdateBy;
    }

    public String getPropNameUpdateTime() {
        return propNameUpdateTime;
    }

    public void setPropNameUpdateTime(String propNameUpdateTime) {
        this.propNameUpdateTime = propNameUpdateTime;
    }

    public void setUniques(String uniques) 
    {
        this.uniques = uniques;
    }

    public String getUniques() 
    {
        return uniques;
    }
    public void setPropIndexMax(Integer propIndexMax) 
    {
        this.propIndexMax = propIndexMax;
    }

    public Integer getPropIndexMax() 
    {
        return propIndexMax;
    }
    public void setRelationIndexMax(Integer relationIndexMax) 
    {
        this.relationIndexMax = relationIndexMax;
    }

    public Integer getRelationIndexMax() 
    {
        return relationIndexMax;
    }
    public void setData(String data) 
    {
        this.data = data;
    }

    public String getData() 
    {
        return data;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
            .append("id", getId())
            .append("no", getNo())
            .append("name", getName())
            .append("idx", getIdx())
            .append("module", getModule())
            .append("status", getStatus())
            .append("description", getDescription())
            .append("propNameName", getPropNameName())
            .append("propNameDel", getPropNameDel())
            .append("propNameNo", getPropNameNo())
            .append("propNameKey", getPropNameKey())
            .append("uniques", getUniques())
            .append("propIndexMax", getPropIndexMax())
            .append("relationIndexMax", getRelationIndexMax())
            .append("data", getData())
            .toString();
    }

    public void addPropNameKey (String columnName) {
        if (RvaUtils.isEmpty(getPropNameKey())) {
            setPropNameKey(columnName);
        } else {
            setPropNameKey(getPropNameKey() + "," + columnName);
        }
    }

    private List<RvaProperty> properties = null;

    private List<RvaRelation> relations = null;

    public void loadData () {
        if (properties == null) {
            RvaProperty search = new RvaProperty();
            search.setObjId(this.getId());
            properties = SpringUtils.getBean(RvaPropertyMapper.class).selectRvaPropertyList(search);
            Collections.sort(properties, new Comparator<RvaProperty>() {
                @Override
                public int compare(RvaProperty o1, RvaProperty o2) {
                    return o1.getIdx() - o2.getIdx();
                }
            });
        }
        if (relations == null) {
            RvaRelation search = new RvaRelation();
            search.setObjId(getId());
            relations = SpringUtils.getBean(RvaRelationMapper.class).selectRvaRelationList(search);
            Collections.sort(relations, new Comparator<RvaRelation>() {
                @Override
                public int compare(RvaRelation o1, RvaRelation o2) {
                    return o1.getIdx() - o2.getIdx();
                }
            });
        }
    }

    public List<RvaProperty> getProperties() {
        loadData();
        return properties;
    }

    public List<RvaRelation> getRelations() {
        loadData();
        return relations;
    }

    public Boolean isPrimaryKey (String propName) {
        String[] split = this.getPropNameKey().split(",");
        return Arrays.asList(split).contains(propName);
    }

    public RvaProperty getPropertyByName (String propName) {
        for (RvaProperty property : getProperties()) {
            if (property.getName().equals(propName)) {
                return property;
            }
        }
        return null;
    }

    public RvaProperty getNameProperty () {
        return getPropertyByName(getPropNameName());
    }

    public Boolean isCreateBy (String propName) {
        return propName.equals(getPropNameCreateBy());
    }

    public Boolean isCreateTime (String propName) {
        return propName.equals(getPropNameCreateTime());
    }

    public Boolean isUpdateBy (String propName) {
        return propName.equals(getPropNameUpdateBy());
    }

    public Boolean isUpdateTime (String propName) {
        return propName.equals(getPropNameUpdateTime());
    }

    public Boolean isNameProp(String propName) {
        return propName.equals(getPropNameName());
    }

    public void initPropNames () {
        if (RvaUtils.isEmpty(getPropNameKey())) {
            setPropNameKey(this.getProperties().get(0).getName());
        }
        if (RvaUtils.isEmpty(getPropNameName())) {
            // Arrays.asList("名称", "姓名", "标题", "name", "title").contains(property.getDescription())
            for (RvaProperty property : getProperties()) {
                if (Arrays.asList("名称", "姓名", "标题", "name", "title").contains(property.getDescription())) {
                    setPropNameName(property.getName());
                }
            }
        }
    }

    public RvaProperty getKeyProperty () {
        for (RvaProperty property : getProperties()) {
            if (isPrimaryKey(property.getName())) {
                return property;
            }
        }
        return null;
    }

    public RvaProperty getProperty (String propId) {
        for (RvaProperty property : getProperties()) {
            if (property.getId().equals(propId)) {
                return property;
            }
        }
        return null;
    }

    public static String getCreateTableSql(RvaObject object) {
        List<RvaProperty> props = object.getProperties();
        String sql = "";
        String ids = "";
        for (RvaProperty prop : props) {
            if (!sql.equals("")) {
                sql += ",\n";
            }
            sql += " " + RvaProperty.getSqlFieldClause(prop, object);
            if (object.isPrimaryKey(prop.getName())) {
                if (ids != "") {
                    ids += ",";
                }
                ids += prop.getName();
            }
        }
        if (ids != "") {
            sql += ",primary key (" + ids + ")";
        }
        sql = "create table " + object.getId() + " (\n" + sql + "\n) comment '" + object.getName() + "'";
        return sql;
    }

    public static String getDropTableSql (RvaObject object) {
        return String.format("drop table if exists %s", object.getId());
    }

    /**
     *
     * @return
     */
    public RvaMap<String, Object> parseData () {
        return RvaUtils.parseMap(this.data);
    }

    public String getPropNameIndex () {
        return parseData().getString("propNameIndex");
    }

    public Boolean hasNotPropIndex () {
        return RvaUtils.isEmpty(getPropNameIndex ());
    }

    public Boolean hasPropIndex () {
        return RvaUtils.isNotEmpty(getPropNameIndex ());
    }

    public List<String> getPropNameIndexWhere () {
        return parseData().getStringList("propNameIndexWhere");
    }

    public String getRequestValue (String propName, RvaMap req) {
        return req.getStringBySuffix(this.getId() + "_" + propName);
    }

    public String getRequestKeyValue (RvaMap req) {
        return getRequestValue(getPropNameKey(), req);
    }

    public String getRequestIndexValue (RvaMap req) {
        return getRequestValue(getPropNameIndex(), req);
    }

    public RvaMap<String, Object> getRequestIndexData (RvaMap req) {
        RvaMap<String, Object> data = new RvaMap<>();
        getPropNameIndexWhere ().forEach(iw -> {
            data.put(iw, getRequestValue(iw, req));
        });
        data.put(getPropNameKey(), getRequestKeyValue(req));
        data.put(getPropNameIndex(), getRequestIndexValue(req));
        return data;
    }
}
